package main

import "fmt"

func f1() int {
	x := 5
	defer func() {
		x++
	}()
	return x // 5
}

/*
执行流程：
在调用 f1() 函数时，会创建一个局部变量 x 并赋值为 5。
接着，遇到 defer 语句。defer 语句会延迟执行一个函数，该函数会在函数执行完毕并且返回结果之前被调用。
在这里，defer 后面的函数会捕获 x 的值，但不会立即执行，而是在 f1() 函数执行完毕后执行。
然后，f1() 函数返回 x 的值，即 5。
最后，延迟执行的函数被调用。在这个函数中，x 的值被增加了 1，但是这个操作对于 f1() 的返回值已经没有影响了，因为返回值已经在此之前确定并返回了。
因此，尽管 defer 语句中的函数对 x 进行了修改，但是对于 f1() 函数的返回值没有影响，最终 f1() 函数返回的结果仍然是 5。
*/

func f2() (x int) {
	defer func() {
		x++
	}()
	return 5 //  6
}

/*
执行流程：
在调用 f2() 函数时，会创建一个命名返回值 x 并赋初值为 0（由于 x 是命名返回值，因此其初始值为类型的零值）。
然后，遇到 defer 语句。defer 语句会延迟执行一个函数，该函数会在函数执行完毕并且返回结果之前被调用。
在这里，defer 后面的函数会捕获命名返回值 x 的地址，并且延迟执行。这意味着，即使 f2() 函数返回后，延迟执行的函数依然能够修改 x 的值。
接着，f2() 函数返回值为 5。因为 x 是命名返回值，因此返回值会被初始化为 0，但在 return 语句中指定的值 5 会覆盖掉初始值。这样，函数返回的结果为 5，但是在此之前延迟执行的函数并未执行。
最后，在函数返回后，延迟执行的函数被调用。在这个函数中，命名返回值 x 被增加了 1，因此 x 的最终值为 6。
因此，尽管 f2() 函数返回的结果为 5，但在函数返回后，由于延迟执行的函数对命名返回值 x 进行了修改，x 的最终值为 6。
*/

func f3() (y int) {
	x := 5
	defer func() {
		x++
	}()
	return x // 5
}

/*
执行流程：
在调用 f3() 函数时，会创建一个局部变量 x 并赋值为 5。
然后，遇到 defer 语句。defer 语句会延迟执行一个函数，该函数会在函数执行完毕并且返回结果之前被调用。
在这里，defer 后面的函数会捕获 x 的值，但不会立即执行，而是在 f3() 函数执行完毕后执行。
接着，f3() 函数返回值为 x 的值，即 5。
最后，在函数返回后，延迟执行的函数被调用。在这个函数中，x 的值被增加了 1，但是这个操作对于 f3() 的返回值已经没有影响了，因为返回值已经在此之前确定并返回了。
因此，尽管 defer 语句中的函数对 x 进行了修改，但是对于 f3() 函数的返回值没有影响，最终 f3() 函数返回的结果仍然是 5。
*/

func f4() (x int) {
	defer func(x int) {
		x++
	}(x)
	return 5 // 5
}

/*
执行流程：
在这个函数中，defer 语句内部的匿名函数接受了一个 int 类型的参数 x，但这个参数是传值的，不会影响到外部的 x。
这是因为在 Go 中函数参数是值传递的，即函数参数会创建一个副本，对参数的修改不会影响原始变量。
所以在 defer 语句内部对 x 的修改不会影响外部的 x。

因此，即使 defer 语句内部的函数对参数 x 进行了自增操作，但这个自增操作对外部的 x 没有影响。
而外部的 x 在 return 语句中指定了返回值为 5，所以函数最终返回的结果是 5。
因此，函数 f4 返回值为 5。 defer 语句内部的函数虽然修改了参数 x，但这个修改不会影响外部的 x，也不会影响到返回值。
*/

func main() {
	fmt.Println(f1()) // 5
	fmt.Println(f2()) // 6
	fmt.Println(f3()) // 5
	fmt.Println(f4()) // 5
}
